package com.mall.b2c.controller;

import static com.mall.b2c.Constants.CART_COOKIE_QUANTITY;
import static com.mall.b2c.Constants.JSESSION_COOKIE;
import static com.mall.b2c.Constants.LOGIN_FAIL_COUNT;
import static com.mall.b2c.Constants.LOGIN_MEMBER_USERNAME_COOKIE_NAME;
import static com.mall.b2c.Constants.LOGIN_TEMP_USERNAME_COOKIE_NAME;
import static com.mall.b2c.Constants.LOGIN_WITH_CODE;
import static com.mall.b2c.Constants.PRINCIPAL_SESSION_NAME;
import static com.mall.b2c.Constants.REDIS_REGISTER_SMS_PREFIX;
import static com.mall.b2c.Constants.REMEMBER_ME_COOKIE;
import static com.mall.b2c.Constants.SMS_RESEND_TIME;

import java.io.IOException;
import java.math.BigDecimal;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.mall.b2c.Constants;
import com.mall.b2c.bean.*;
import com.mall.b2c.hessian.*;
import com.mall.b2c.util.VerifyUtil;
import com.mall.common.enums.FieldType;
import com.mall.common.util.JsonUtil;
import com.mall.common.validation.annotation.SpecialRegexFieldValidator;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;
import com.mall.b2c.util.CacheUtils;
import com.mall.common.bean.Message;
import com.mall.common.exception.NoticeException;
import com.mall.common.service.MyCaptchaService;
import com.mall.common.service.RSAService;
import com.mall.common.util.AppContext;
import com.mall.common.util.CookieUtils;
import com.mall.common.util.ResponseUtils;
import com.mall.common.validation.annotation.RequiredStringValidator;
import com.mall.common.validation.annotation.Validations;

@Controller
public class IndexController extends BaseController {
	@Resource private CacheService cacheService;
	@Resource private RSAService rsaService;
	@Resource private MyCaptchaService captchaService;
	@Resource private TradeHessian tradeHessian;
	@Resource private ContentHessian contentHessian;
	@Resource private RedisTemplate<String, String> redisTemplate;
	@Resource private StoreHessian storeHessian;
	@Resource private CardHessian cardHessian;

	private String[] entryIP = { "127.0.0.1"};
	
	@RequestMapping("/index")
	public String index(Model model){
		cacheService.getSystemConfig();
		/*if(storeId!=null){
			StoreBean store = jsonToObj(storeHession.getStoreInfo(storeId), StoreBean.class);
			if(store == null) {
				String cityJson = storeHession.getDefaultCity("");
				StoreCityBean city = jsonToObj(cityJson, StoreCityBean.class);
				store = city.getStores().get(0);
				AppContext.setSessionAttr(Constants.CURR_STORE_SESSION_KEY, store);
				AppContext.setSessionAttr(Constants.CURR_STORE_CITY_SESSION_KEY, city);
			}else{
				store = jsonToObj(storeHession.getDefaultStore(""), StoreBean.class);
				String cityJson = storeHession.getDefaultCityById(store.getCityId());
				StoreCityBean city = jsonToObj(cityJson, StoreCityBean.class);
				store = city.getStores().get(0);
				AppContext.setSessionAttr(Constants.CURR_STORE_SESSION_KEY, store);
				AppContext.setSessionAttr(Constants.CURR_STORE_CITY_SESSION_KEY, city);
			}
		}*/
		return "/index";
	}
	
	/**
	 * 会员注册页面
	 * @return
	 */
	@RequestMapping("/register")
	public String register(Model model){
		model.addAttribute("captchaId", UUID.randomUUID().toString());
		return "/register";
	}

	
	/**
	 * 验证验证码
	 * @param captchaId 
	 * @param captcha 验证码
	 * @return
	 */
	@RequestMapping(value="/checkCaptcha",method=RequestMethod.POST)
	@ResponseBody
	public JSONObject checkCaptcha(String captchaId, String captcha, HttpSession session){
		JSONObject jObj = new JSONObject();
		if(captchaService.isValid(captchaId, captcha)){
			session.setAttribute(captchaId, true);
			jObj.put("result", true);
		}
		return jObj;
	}
	
	/**
	 * 短信验证码
	 * @param mobile 手机号码
	 * @return
	 */
	@Validations(
			requiredStrings = {
					@RequiredStringValidator(fieldName="mobile",message="手机号码不正确"),
					@RequiredStringValidator(fieldName="captchaId",message="请先验证验证码")
			}
	)
	@RequestMapping(value="/sendRegisterSms",method=RequestMethod.POST)
	@ResponseBody
	public Message sendRegisterSms(String captchaId, String mobile){
		/*if(AppContext.getSessionAttr(captchaId) == null){
			throw new NoticeException("请先验证验证码");
		}*/
		ValueOperations<String, String> vo = redisTemplate.opsForValue();
		String key = REDIS_REGISTER_SMS_PREFIX + mobile;
		long expiredTime = redisTemplate.getExpire(key);
		if(expiredTime > SMS_RESEND_TIME){
			return Message.error("请不要频繁发送验证码");
		}
		JSONObject codeInfo = JSONObject.parseObject(memberHessian.sendMobileCaptcha(mobile, AppContext.getRemoteIp(), Boolean.TRUE, null, 0));
		vo.set(key, codeInfo.getString("validateCode"), codeInfo.getLong("expired"), TimeUnit.MILLISECONDS);
		return successMessage;
	}

	/**
	 * 
	 * 会员注册
	 * @param mobile 手机号码
	 * @param code 手机验证码
	 * @param password 密码
	 * @param captchaId 验证码id
	 * @param request
	 * @param response
	 * @return
	 */
	@Validations(
			requiredStrings = {
					@RequiredStringValidator(fieldName="mobile",message="手机号码不正确"),
					@RequiredStringValidator(fieldName="captcha",message="请输入图形验证码"),
					@RequiredStringValidator(fieldName="code",message="请输入验证码"),
					@RequiredStringValidator(fieldName="password",message="请输入密码"),
					@RequiredStringValidator(fieldName="captchaId",message="请先验证验证码")
			}
	)
	@RequestMapping(value="/registerVerify", method=RequestMethod.POST)
	@ResponseBody
	public Message registerVerify(String mobile, String code,String captcha, String password, Boolean remember,
			String captchaId, HttpServletRequest request, HttpServletResponse response,HttpSession session){

		if(!captchaService.isValid(captchaId, captcha)){
			//session.setAttribute(captchaId, true);
			throw new NoticeException("图形验证码错误");
		}
		/*if(AppContext.getSessionAttr(captchaId) == null){
			throw new NoticeException("请先验证验证码");
		}*/
		ValueOperations<String, String> vo = redisTemplate.opsForValue();
		String validateCode = vo.get(REDIS_REGISTER_SMS_PREFIX + mobile);
		if(StringUtils.isBlank(validateCode)){
			throw new NoticeException("验证码已失效");
		}
		if(!validateCode.equals(code)){
			throw new NoticeException("验证码不正确");
		}
		password = rsaService.decryptParameter(password);


		Cookie inviterNameCookie = CookieUtils.getCookie(request, Constants.INVITE_COOKIE_NAME);
		Long inviter_id = null;
		if(inviterNameCookie != null){
			String inviterName = inviterNameCookie.getValue();
			if(Pattern.compile("^\\d+$").matcher(inviterName).matches()){
				inviter_id = Long.valueOf(inviterName);
			}
		}

		String result = memberHessian.register(mobile, password, AppContext.getRemoteIp(), inviter_id);
		MemberBean memberBean = jsonToObj(result, MemberBean.class);
		if(inviterNameCookie != null){
			CookieUtils.removeCookie(request, response, Constants.INVITE_COOKIE_NAME);
		}
		loginSuccess(memberBean, memberBean.getUsername(), remember, request, response);
		return successMessage;
	}
	
	/**
	 * 登录成功操作
	 * @param member 会员信息
	 * @param username 登录用户名
	 * @param remember 是否记住密码
	 * @param request
	 * @param response
	 */
	private void loginSuccess(MemberBean member, String username, Boolean remember,
			HttpServletRequest request, HttpServletResponse response){
		HttpSession session = request.getSession();

		Principal principal = new Principal(member.getId(), member.getUsername());
		session.setAttribute(PRINCIPAL_SESSION_NAME, principal);
		CookieUtils.addCookie(request, response, REMEMBER_ME_COOKIE, username, 604800, null);
		String loginName = member.getUsername();
		if(StringUtils.isNotBlank(member.getName())){
			loginName = member.getName();
		}
		Cookie cookie = CookieUtils.getCookie(request, JSESSION_COOKIE);
		if(remember != null && remember){
			CookieUtils.addCookie(request, response, JSESSION_COOKIE, cookie.getValue(), 604800, null);
			session.setMaxInactiveInterval(604800);
			CookieUtils.addCookie(request, response, LOGIN_MEMBER_USERNAME_COOKIE_NAME, loginName, 604800, null);
		}else{
			CookieUtils.addCookie(request, response, LOGIN_MEMBER_USERNAME_COOKIE_NAME, loginName);
		}
		//清空指定用户登录失败计数缓存
		isValidateCodeLogin(username, false, true);
		CookieUtils.removeCookie(request, response, LOGIN_TEMP_USERNAME_COOKIE_NAME);
	}
	
	/**
	 * 登录页面
	 * @return
	 */
	@RequestMapping("/login")
	public String login(String redirectUrl, Model model, HttpServletRequest request, HttpServletResponse response){
		if(getPrincipal() != null){
			MemberBean member = getMember();
			loginSuccess(member, member.getUsername(), false, request, response);
			return "redirect:index.jhtml";
		}
		String captchaId = UUID.randomUUID().toString();
		model.addAttribute("captchaId", captchaId);
		model.addAttribute("redirectUrl", StringEscapeUtils.escapeHtml4(redirectUrl));

		String username = CookieUtils.get(request, LOGIN_TEMP_USERNAME_COOKIE_NAME);
		model.addAttribute("showCode", isValidateCodeLogin(username, false, false));
		return "/login";
	}
	
	/**
	 * 会员登陆
	 * @param username 用户名
	 * @param password 密码
	 * @return
	 */
	@Validations(
			requiredStrings = {
					@RequiredStringValidator(fieldName="username",message="用户名错误"),
					@RequiredStringValidator(fieldName="password",message="密码错误")
			}
	)
	@RequestMapping(value="/loginVerify", method=RequestMethod.POST)
	@ResponseBody
	public JSONObject loginVerify(String username, String password, String captchaId, 
			String captcha, Boolean remember, HttpServletRequest request, HttpServletResponse response){

		CookieUtils.addCookie(request, response, LOGIN_TEMP_USERNAME_COOKIE_NAME, username, 3600, null);
		JSONObject jObj = new JSONObject();
		try {
			if (isValidateCodeLogin(username, false, false) && !captchaService.isValid(captchaId, captcha)) {
				throw new NoticeException("验证码错误");
			}
			password = rsaService.decryptParameter(password);
			String result = memberHessian.login(username, password, AppContext.getRemoteIp());
			MemberBean member = jsonToObj(result, MemberBean.class);
			loginSuccess(member, username, remember, request, response);
		} catch (NoticeException e) {
			jObj.put("error", e.getMessage());
			jObj.put("showCode", isValidateCodeLogin(username, true, false));
		}

		return jObj;
	}

	/**
	 * 是否验证码登录
	 * @param username 用户名
	 * @param isFail 计数加1
	 * @param clean 计数清零
	 * @return
	 */
	private boolean isValidateCodeLogin(String username, boolean isFail, boolean clean){
		Integer failCount = (Integer) CacheUtils.getCacheValue(LOGIN_FAIL_COUNT, username);
		if (failCount==null){
			failCount = 0;
		}
		if (isFail){
			failCount++;
			CacheUtils.setCacheValue(LOGIN_FAIL_COUNT, username, failCount);
		}
		if (clean){
			CacheUtils.cleanEhCache(LOGIN_FAIL_COUNT, username);
		}
		return failCount >= LOGIN_WITH_CODE;
	}

	/**
	 * 会员登出
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value="/logout", method=RequestMethod.POST)
	@ResponseBody
	public Message logout(HttpServletRequest request, HttpServletResponse response){
		AppContext.removeAttribute(PRINCIPAL_SESSION_NAME);
		CookieUtils.removeCookie(request, response, LOGIN_MEMBER_USERNAME_COOKIE_NAME);
		CookieUtils.removeCookie(request, response, REMEMBER_ME_COOKIE);
		CookieUtils.removeCookie(request, response, JSESSION_COOKIE);
		return successMessage;
	}
	
	/**
	 * 获取验证码
	 * @param captchaId
	 * @param request
	 * @param response
	 */
	@RequestMapping("/captcha")
	public void captcha(String captchaId, HttpServletRequest request, HttpServletResponse response) {
		if (StringUtils.isEmpty(captchaId)){
			captchaId = request.getSession().getId();
		}
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Cache-Control", "no-store");
		response.setDateHeader("Expires", 0L);
		response.setContentType("image/jpeg");
		ServletOutputStream servletoutputstream = null;
		try {
			servletoutputstream = response.getOutputStream();
			java.awt.image.BufferedImage bufferedimage = captchaService.buildImage(captchaId);
			ImageIO.write(bufferedimage, "jpg", servletoutputstream);
			servletoutputstream.flush();
		} catch (Exception exception) {
			exception.printStackTrace();
		} finally {
			IOUtils.closeQuietly(servletoutputstream);
		}
	}
	
	/**
	 * 加密
	 * @param request
	 * @return
	 */
	@RequestMapping("/publicKey")
	@ResponseBody
	public JSONObject publicKey(HttpServletRequest request){
		RSAPublicKey rsapublickey = rsaService.generateKey(request, false);
		JSONObject obj = new JSONObject();
		obj.put("modulus", Base64.encodeBase64String(rsapublickey.getModulus().toByteArray()));
		obj.put("exponent", Base64.encodeBase64String(rsapublickey.getPublicExponent().toByteArray()));
		return obj;
	}
	
	/**
	 * 地区级联
	 * @param path
	 * @param response
	 * @return
	 */
	@RequestMapping(value="/area", method=RequestMethod.GET)
	public String area(Long path, HttpServletResponse response) {
		return ResponseUtils.renderJSON(cacheService.getAreaByParentId(path), response);
	}

	@RequestMapping("/error")
	public String error(){
		return "/error";
	}

	/**
	 * 刷新购物车数量
	 * @return
	 */
	@RequestMapping("/refreshCart")
	@ResponseBody
	public String getCartItemInfo(HttpServletRequest request, HttpServletResponse response){
		Principal principal = (Principal) AppContext.getSessionAttr(PRINCIPAL_SESSION_NAME);
		if(principal != null){
			CartBean cart = jsonToObj(tradeHessian.getCartItemInfo(getMemberId(), null, false), CartBean.class);
			Integer quantity = cart.getItemNum();
			CookieUtils.addGlobalCookie(request, response, CART_COOKIE_QUANTITY, Integer.toString(quantity), null);
		}else{
			CookieUtils.addGlobalCookie(request, response, CART_COOKIE_QUANTITY, "0", null);
		}
		return ResponseUtils.renderJSON(successMessage, response);
	}

	@RequestMapping("/help/{id}")
	public String help(@PathVariable Long id, Model model, HttpServletResponse response) throws IOException{
		try {
			model.addAttribute("article", jsonToObj(contentHessian.getArticleBean(id), ArticleBean.class));
		} catch (NoticeException e) {
			response.sendError(404);
			return null;
		}
		return "/article/help";
	}

	@RequestMapping("/article/list")
	public String list(Integer pageNumber, Model model){
		model.addAttribute("pager", jsonToObj(contentHessian.getArticlePager("b2c.ggtz", true, pageNumber, 20, "releaseDate"), Pager.class));
		return "/article/list";
	}

	@RequestMapping("/news/{id}")
	public String news(@PathVariable Long id, Model model){
		model.addAttribute("article", jsonToObj(contentHessian.getArticleBean(id), ArticleBean.class));
		return "/article/detail";
	}

	@RequestMapping("/cleanArticleCache")
	@ResponseBody
	public Message cleanArticleCache(String[] pathes){
		String ip = AppContext.getRemoteIp();
		String domain = cacheService.getSystemConfig().getDomainAlias();
		for(String str : entryIP){
			if(str.equals(ip) || domain.equals(ip)){
				if(pathes == null){
					return errorMessage;
				}
				for(String path	: pathes){
					CacheUtils.cleanEhCache("OftenPageCachingFilter", path);
				}
			}
		}
		return successMessage;
	}

	@RequestMapping("/cleanPageCache")
	@ResponseBody
	public Message cleanPageCache(){
		String ip = AppContext.getRemoteIp();
		String domain = cacheService.getSystemConfig().getDomainAlias();
		for(String str : entryIP){
			if(str.equals(ip) || domain.equals(ip)){
				CacheUtils.clearCache("SimplePageCachingFilter");
				CacheUtils.clearCache("OftenPageCachingFilter");
			}
		}
		return successMessage;
	}

	@RequestMapping("/car")
	public String car(){
		return "car/index";
	}


	@RequestMapping("/city/stores")
	@ResponseBody
	public String stores(Long cityId, HttpServletRequest request, HttpServletResponse response){
		StoreCityBean bean = jsonToObj(storeHessian.getDefaultCityById(cityId), StoreCityBean.class);
		if(bean != null){
			return bean.getStores().get(0).getId()+"";
		}
		return "";
	}
	@RequestMapping("/city/storesjson")

	public String storesjson(Long cityId, HttpServletRequest request, HttpServletResponse response){
		StoreCityBean bean = jsonToObj(storeHessian.getDefaultCityById(cityId), StoreCityBean.class);
		return ResponseUtils.renderJSON(bean, response);
		//return JsonUtil.getInstance().obj2json(bean);
		//return ResponseUtils.renderJSON(bean, response);
	}



	@Validations(
			requiredStrings = {
					@RequiredStringValidator(fieldName="mobile",message="手机号码不正确"),
					@RequiredStringValidator(fieldName="year",message="请输入提车年份"),
					@RequiredStringValidator(fieldName="month",message="请输入提车月份"),
					@RequiredStringValidator(fieldName="price",message="请输入车价"),
					@RequiredStringValidator(fieldName="city",message="请输入行驶城市")
			},
			specials = {
					@SpecialRegexFieldValidator(fieldName="mobile",fieldType= FieldType.mobileOrTelephone,message="手机号码格式不正确")
			}
	)
	@RequestMapping("/car/add")
	@ResponseBody
	public Message carAdd(String city, String carNo, String year, String month, Double price, String mobile){

		if(!VerifyUtil.IsYear(year)){
			return Message.error("年份不正确");
		}

		if(!VerifyUtil.IsMonth(month)){
			return Message.error("月份格式不正确");
		}

		cardHessian.carAdd(city,carNo,year,month,price,mobile);
		return successMessage;
	}
}
